package com.sc.nft.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.*;
import com.sc.nft.dto.SendMessageOneDataReq;
import com.sc.nft.dto.SendMessageOneReq;
import com.sc.nft.entity.DigitalCollectionProductInfo;
import com.sc.nft.entity.DigitalCollectionProductInfoSubscribe;
import com.sc.nft.entity.ProductStock;
import com.sc.nft.entity.dto.DigitalCollectionProductInfoSubscribeCodeDTO;
import com.sc.nft.entity.dto.DigitalCollectionProductInfoSubscribeCodeRequest;
import com.sc.nft.entity.vo.DigitalCollectionProductInfoSubscribeCodeSummaryVO;
import com.sc.nft.entity.vo.DigitalCollectionProductInfoSubscribeCodeVo;
import com.sc.nft.entity.vo.ProductIdAndMaxSubscribeByUserIdAndCountVO;
import com.sc.nft.entity.vo.WinningUsersVO;
import com.sc.nft.enums.ActivityStatusEnum;
import com.sc.nft.enums.ClassifyType;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.enums.StockType;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.feign.SmsFeignClient;
import com.sc.nft.req.TencentSendSmsReq;
import com.sc.nft.service.DigitalCollectionProductInfoSubscribeCodeService;
import com.sc.nft.vo.WinNoticePeopleVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 用户申购码(DigitalCollectionProductInfoSubscribeCode)表服务实现类
 *
 * @author 王伟成
 * @since 2024-05-15 18:32:39
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class DigitalCollectionProductInfoSubscribeCodeServiceImpl implements DigitalCollectionProductInfoSubscribeCodeService {

    private final DigitalCollectionProductInfoSubscribeCodeDao digitalCollectionProductInfoSubscribeCodeDao;

    private final DigitalCollectionProductInfoSubscribeWinBallotDao digitalCollectionProductInfoSubscribeWinBallotDao;

    private final DigitalCollectionProductInfoDao digitalCollectionProductInfoDao;

    private final ProductStockDao productStockDao;

    private final DigitalCollectionProductInfoSubscribeDao digitalCollectionProductInfoSubscribeDao;

    private final SmsFeignClient smsFeignClient;

    private final Redisson redisson;

    @Override
    public Page<DigitalCollectionProductInfoSubscribeCodeVo> getSubscribeCodePage(DigitalCollectionProductInfoSubscribeCodeDTO request) {
        Page<DigitalCollectionProductInfoSubscribeCodeVo> subscribeCodePage = digitalCollectionProductInfoSubscribeCodeDao.getSubscribeCodePage(request);
        List<DigitalCollectionProductInfoSubscribeCodeVo> records = subscribeCodePage.getRecords();
        if (ObjectUtil.isNotNull(records)) {
            records.forEach(record -> {
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                record.setActivityTime(simpleDateFormat.format(record.getSubscribeStartTime()) + "~" + simpleDateFormat.format(record.getEndTime()));
                if (new Date().before(record.getSubscribeStartTime())) {
                    record.setActivityStatus(ActivityStatusEnum.NOT_STARTED_YET);
                } else if (new Date().after(record.getEndTime())) {
                    record.setActivityStatus(ActivityStatusEnum.ENDED);
                } else {
                    record.setActivityStatus(ActivityStatusEnum.IN_PROGRESS);
                }
            });
        }
        return subscribeCodePage;
    }

    @Override
    public DigitalCollectionProductInfoSubscribeCodeSummaryVO getSubscribeCodeSummary(Long id) {
        Assert.isTrue(ObjectUtil.isNotNull(digitalCollectionProductInfoDao.getById(id)), () -> new GlobalRunTimeException("该申购活动不存在！"));
        return digitalCollectionProductInfoSubscribeWinBallotDao.getSubscribeCodeSummary(id);
    }

    @Override
    public Page<WinningUsersVO> getSubscribeCodeUserPage(DigitalCollectionProductInfoSubscribeCodeRequest request) {
        Assert.isTrue(ObjectUtil.isNotNull(digitalCollectionProductInfoDao.getById(request.getId())), () -> new GlobalRunTimeException("该申购活动不存在！"));
        return digitalCollectionProductInfoSubscribeWinBallotDao.getSubscribeCodeUserPage(request);
    }

    /**
     * 抽签
     *
     * @param productId 商品id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean drawLots(Long productId) {
        String key = RedisKeyEnum.DRAW_LOTS.getKey() + productId;
        RLock lock = redisson.getLock(key);
        try {
            if (!lock.tryLock(3, TimeUnit.SECONDS)) {
                return false;
            }
            DigitalCollectionProductInfoSubscribe digitalCollectionProductInfoSubscribe = digitalCollectionProductInfoSubscribeDao.getByProductInfoSubscribe(productId);
            if (digitalCollectionProductInfoSubscribe.getIsDraw()) {
                return false;
            }
            DigitalCollectionProductInfo digitalCollectionProductInfo = digitalCollectionProductInfoDao.getById(productId);
            if (ObjectUtil.isNull(digitalCollectionProductInfo)) {
                throw new GlobalRunTimeException("商品不存在");
            }
            ProductStock productStock = null;
            if (digitalCollectionProductInfo.getTypeClassify() == ClassifyType.BLIND_BOX) {
                productStock = productStockDao.getByProductIdAndStockType(productId, StockType.BLIND_BOX);
            } else {
                // 获取商品库存对象
                productStock = productStockDao.getByProductId(productId);
            }
            // 所有用户都变更为抽签中
            Boolean b = digitalCollectionProductInfoSubscribeCodeDao.updateSchedule(productId);
            // 申购基础数据
            if (!b) {
                // 申购的基础数据,标记已抽
                digitalCollectionProductInfoSubscribeDao.updateIsDraw(productId);
                return false;
            }else {
                // 商品库存
                Integer usableCount = productStock.getUsableCount();
                Set<Long> excludeUserId = new HashSet<>();
                // 请注意,这里调用了的方法是递归方法.
                recursiveDrawing(productId, usableCount, digitalCollectionProductInfoSubscribe, excludeUserId);
                // 把本期中签的数据,批量写入到中签表里面
                digitalCollectionProductInfoSubscribeCodeDao.toWinABallotCopyResult(productId);
                // 把本期所有的非中签数据,改为未中签
                digitalCollectionProductInfoSubscribeCodeDao.drawBlank(productId);
                // 申购的基础数据,标记已抽
                digitalCollectionProductInfoSubscribeDao.updateIsDraw(productId);
                return true;
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean resultAnnounceSendMessage(WinNoticePeopleVo winNoticePeopleVo,Long productId) {
//        List<String> messages = new ArrayList<>();
        Date subscribeStartTime = winNoticePeopleVo.getSubscribeStartTime();
        Date endTime = winNoticePeopleVo.getEndTime();
        SimpleDateFormat activityStartTime = new SimpleDateFormat("MM月dd日");
        SimpleDateFormat activityEndTime = new SimpleDateFormat("MM月dd日 HH:mm:ss");
//        messages.add(activityStartTime.format(subscribeStartTime));
//        messages.add(activityEndTime.format(endTime));
//        SendMessageOneReq sendMessageOneReq = new SendMessageOneReq();
//        SendMessageOneDataReq sendMessageMassReq = new SendMessageOneDataReq();
//        sendMessageMassReq.setPhone(winNoticePeopleVo.getUserTel());
//        sendMessageMassReq.setContentVariable(messages);
//        sendMessageMassReq.setTemplateId(4155L);
//        List<SendMessageOneDataReq> sendMessageOneDataReqList = new ArrayList<>();
//        sendMessageOneDataReqList.add(sendMessageMassReq);
//        sendMessageOneReq.setTemplateId(4155L);
//        sendMessageOneReq.setMessageOneSendList(sendMessageOneDataReqList);
//        smsFeignClient.sendMessageOne(sendMessageOneReq);
        String[] data = {activityStartTime.format(subscribeStartTime),activityEndTime.format(endTime)};
        TencentSendSmsReq tencentSendSmsReq = new TencentSendSmsReq();
        tencentSendSmsReq.setPhoneNumber(winNoticePeopleVo.getUserTel());
        tencentSendSmsReq.setTemplateId("2231923");
        tencentSendSmsReq.setData(data);
        smsFeignClient.tencentSend(tencentSendSmsReq);
        digitalCollectionProductInfoSubscribeWinBallotDao.updateStatusById(winNoticePeopleVo.getUserId());
        return Boolean.TRUE;
    }



    public void recursiveDrawing(Long productId, Integer sumCount, DigitalCollectionProductInfoSubscribe digitalCollectionProductInfoSubscribe, Set<Long> excludeUserId) {
        Integer drawLotsSum = 0;
        // 数据库随机修改sumCount个数的中签状态,在对他进行重复性的筛选
        digitalCollectionProductInfoSubscribeCodeDao.drawLots(productId, sumCount, excludeUserId);
        // 每个人最大中签的数量
        Integer maxSubscribe = digitalCollectionProductInfoSubscribe.getMaxSubscribe();
        //  获取所有中签的用户大于最大中签数量的用户
        List<ProductIdAndMaxSubscribeByUserIdAndCountVO> productIdAndMaxSubscribeByUserIdAndCount = digitalCollectionProductInfoSubscribeCodeDao.getProductIdAndMaxSubscribeByUserIdAndCount(productId, maxSubscribe, excludeUserId);
        if (CollUtil.isEmpty(productIdAndMaxSubscribeByUserIdAndCount)) {
            return;
        }
        // 当productIdAndMaxSubscribeByUserIdAndCount不为空的时候,意味着有人抽超了.那么就把他超的部分给收回来
        for (ProductIdAndMaxSubscribeByUserIdAndCountVO productIdAndMaxSubscribeByUserIdAndCountVO : productIdAndMaxSubscribeByUserIdAndCount) {
            // 把用户当前拥有的,和最大的比对,多出的部分,减去并且加回到drawLotsSum里面,并且干掉对应用户的对应抽签码中签数量的记录变为未中签
            if (productIdAndMaxSubscribeByUserIdAndCountVO.getCount() > maxSubscribe) {
                // 扣除对应的数量
                Integer takeOut = productIdAndMaxSubscribeByUserIdAndCountVO.getCount() - maxSubscribe;
                Boolean b = digitalCollectionProductInfoSubscribeCodeDao.takeOut(productIdAndMaxSubscribeByUserIdAndCountVO.getUserId(), productId, takeOut);
                if (!b) {
                    throw new GlobalRunTimeException("用户申购码异常扣除失败");
                }
                drawLotsSum += takeOut;
                // 得到了申购码中签上限的用户就直接排除了,这很有可能排除很大一批人和数据
                excludeUserId.add(productIdAndMaxSubscribeByUserIdAndCountVO.getUserId());
            }
        }
        // 如果drawLotsSum不为0,那么就递归调用
        if (drawLotsSum != 0) {
            recursiveDrawing(productId, drawLotsSum, digitalCollectionProductInfoSubscribe, excludeUserId);
        }
    }
}
